/*
 * $LastChangedDate: 2007-06-20 16:57:30 +0200 (Wed, 20 Jun 2007) $
 * $LastChangedRevision: 196 $
 * $LastChangedBy: david $
 */

import java.io.*;
import java.util.*;


public class Main
{
        // variable que controla cuando hay que finalizar la simulacion
        public static boolean acabar = false;    
    
	private static Server myServer = new Server("Server");

	/* Contiene los clientes creados listos para ejecutar */
	private static ArrayList<Client> readyClients = new ArrayList<Client>();

	/* Para leer del teclado */
	private static BufferedReader kb_br = new BufferedReader(new InputStreamReader(System.in));

	/**
	 * Añade un nuevo cliente a la lista de clientes listos para ser ejecutados.
	 */
	private static void addClient(String path, String mode)
	{
		Client newClient;

		newClient = new Client(path, mode);
		readyClients.add(newClient);
	}

	/**
	 * Crea un nuevo cliente según los parámetros introducidos desde el
	 * teclado
	 */
	private static void createClient()
	{
		String path, mode;

		try {
			System.out.print("Fichero para el cual el cliente debe"
					+ " hacer una petición:\n> ");
			path = kb_br.readLine();
			do {
				System.out.print("Tipo de petición 'r'/'rw':\n> ");
				mode = kb_br.readLine();
			} while (!mode.equals("r") && !mode.equals("rw"));
			addClient(path, mode);
		} catch (IOException e) {
			System.out.println(e);
		}
	}

	/**
	 * Pide al usuario el path hacia un fichero de configuración y crea una
	 * serie de clientes tal como se indica en dicho fichero. El formato
	 * del fichero de configuración es el siguiente: cada línea contiene el
	 * path hacia el fichero que se debe abrir, un espacio en blanco y el
	 * modo en que se debe abrir el fichero.
	 */
	private static void createClientsFromFile()
	{
		String config; /* Path del fichero de configuracion */
		String path; /* Path leído del fichero de configuración */
		String mode; /* Modo leído del fichero de configuración */
		StringTokenizer st;


		try {
			System.out.print("Fichero de configuración:\n> ");
			config = kb_br.readLine();
			FileReader f = new FileReader(config);
			BufferedReader config_br = new BufferedReader(f);

			String line;
			line = config_br.readLine();
			while (line != null) {
				st = new StringTokenizer(line);
				while (st.hasMoreTokens()) {
					path = st.nextToken();
					mode = st.nextToken();
					addClient(path, mode);
				}
				line = config_br.readLine();
			}
		} catch (IOException e) {
			System.out.println(e);
		}
	}

	/**
	 * Imprime el menú con las opciones introducibles desde el teclado
	 */
	private static void printMenu()
	{
		System.out.println("c: crear cliente");
		System.out.println("f: crear clientes a partir de un fichero de configuración");
		System.out.println("s: start clientes");
		System.out.println("l: listar clientes listos para ejecutar");
		System.out.println("v: fijar el nivel de log");
		System.out.println("q: quit");
		System.out.print("> ");
	}

	/**
	 * Lista los clientes listos para ser ejecutados.
	 */
	private static void listClients()
	{
		System.out.println(readyClients);
	}

	/**
	 * Empieza a ejecutar los clientes creados
	 */
	private static void startClients()
	{
		for (int i = 0; i < readyClients.size(); i++) {
			Client cl = (Client) readyClients.get(i);
			cl.start();
		}
		readyClients.clear();
	}

	private static void setLogLevel() throws IOException
	{
		boolean back = false;
		int lvl = 0;
		do {
			System.out.print("1: Toggle INIT log");
			if (Log.isEnabled(Log.INIT)) {
				System.out.println(" (Habilitado)");
			} else {
				System.out.println(" (Deshabilitado)");
			}
			System.out.print("2: Toggle CONNECTION log");
			if (Log.isEnabled(Log.CONNECTION)) {
				System.out.println(" (Habilitado)");
			} else {
				System.out.println(" (Deshabilitado)");
			}

			System.out.print("3: Toggle IO log");
			if (Log.isEnabled(Log.IO)) {
				System.out.println(" (Habilitado)");
			} else {
				System.out.println(" (Deshabilitado)");
			}

			System.out.print("4: Toggle LOCK log");
			if (Log.isEnabled(Log.LOCK)) {
				System.out.println(" (Habilitado)");
			} else {
				System.out.println(" (Deshabilitado)");
			}

			System.out.println("q: volver al menú principal");
			System.out.print("> ");
			String input = kb_br.readLine();
			switch (input.charAt(0)) {
			case '1':
				lvl = Log.INIT;
				break;
			case '2':
				lvl = Log.CONNECTION;
				break;
			case '3':
				lvl = Log.IO;
				break;
			case '4':
				lvl = Log.LOCK;
				break;
			case 'q':
				back = true;
				break;
			default:
				lvl = 0;
				break;
			}
			if (!back && (lvl != 0)) {
				Log.loglevel ^= lvl;
			}
		} while (!back);
		printMenu();
	}

	public static void main(String[] args)
	{
		/* true cuando hay que finalizar el programa */
		boolean end = false;

		myServer.start();

		/* Variable para leer del teclado */
		String input;

		printMenu();
		do {
			/* Leer del teclado */
			try {
				input = kb_br.readLine();

				switch (input.charAt(0)) {
				case 'c':
					createClient();
					break;
				case 'f':
					createClientsFromFile();
					break;
				case 's':
					startClients();
					break;
				case 'l':
					listClients();
					printMenu();
					break;
				case 'q':
					end = true;
                                        // indicar a los clientes que aun esten activos que vayan acabando
                                        acabar = true;
					break;
				case 'v':
					setLogLevel();
					break;
				default:
					printMenu();
					break;
				}
			} catch (IOException e) {
				System.out.println(e);
			} catch (StringIndexOutOfBoundsException e) {
				printMenu();
			}
			
		} while (!end);
		
                // llamar a myServer.interrupt() no funciona ya que cuando el servidor esta bloqueado 
                // en el accept no detecta la condicion de fin, por eso lo detenemos y recogemos la 
                // excepcion SocketException que se lanza en el mismo servidor.
                try{
                    myServer.serverSocket.close();
                } catch (Exception e){}
                
	}
}
